﻿// /********************************************************
// *                                                       *
// *   Copyright (C) Microsoft. All rights reserved.       *
// *                                                       *
// ********************************************************/

using System;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.ServiceModel;
using TelemetryService;

namespace TelemetryService
{
    [ServiceContract(SessionMode = SessionMode.Required)]
    public interface IMarker
    {
        [OperationContract(IsInitiating = true, IsTerminating = false, IsOneWay = true)]
        void InitiateSession();
        [OperationContract(IsInitiating = false, IsTerminating = false, IsOneWay = true)]
        void GenerateSessionSnapshot(MarkerStamp data);
        [OperationContract(IsInitiating = true, IsTerminating = false, IsOneWay = true)]
        void GenerateSnapshot(MarkerStamp data);
        [OperationContract(IsInitiating = false, IsTerminating = true, IsOneWay = true)]
        void FlushAndCloseSession();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class MarkerService : IMarker
    {
        // Should be set to bigger number like 100
        private const int SessionDataBufferMaxLength = 1;

        private static EventLog s_eventLogger = new EventLog();

        private DataTable m_perfDataBuffer;

        private SqlConnection m_connection;

        public static void Log(string message)
        {
            if (!EventLog.SourceExists("Telemetry"))
            {
                EventLog.CreateEventSource("Telemetry", "QE");
            }

            s_eventLogger.Source = "Telemetry";

            s_eventLogger.WriteEntry(message);
        }

        public static void LogToConsole(string message, ConsoleColor color)
        {
            Console.ForegroundColor = color;

            Console.WriteLine(message);

            Console.ResetColor();
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public void InitiateSession()
        {
            m_perfDataBuffer = DbUtility.CreatePerformanceMemoryTable();

            try
            {
                using (m_connection = new SqlConnection(DbUtility.GetConnectionString()))
                {
                    m_connection.Open();

                    LogToConsole("Buffer is created and connection is opened", ConsoleColor.Gray);
                }
            }
            catch (Exception ex)
            {
                LogToConsole(ex.Message, ConsoleColor.Yellow);
            }
        }

        public void GenerateSessionSnapshot(MarkerStamp data)
        {
            // add data as a new row in DataTable
            m_perfDataBuffer.Rows.Add(DbUtility.ConvertToObjects(data, OperationContext.Current.SessionId));

            // save the whole buffer in database
            if (m_perfDataBuffer.Rows.Count >= SessionDataBufferMaxLength)
            {
                DbUtility.BulkDatabaseSaveInTransaction(m_connection, m_perfDataBuffer);
                m_perfDataBuffer.Rows.Clear();

                LogToConsole("Bulk save transaction is finished", ConsoleColor.Gray);
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public void GenerateSnapshot(MarkerStamp data)
        {
            if (m_perfDataBuffer == null)
            {
                m_perfDataBuffer = DbUtility.CreatePerformanceMemoryTable();

                LogToConsole("Created new buffer", ConsoleColor.Gray);
            }

            bool isConnected = false;
            if (m_connection == null || m_connection.State != ConnectionState.Open)
            {
                try
                {
                    using (m_connection = new SqlConnection(DbUtility.GetConnectionString()))
                    {
                        m_connection.Open();

                        LogToConsole("Opened new connection", ConsoleColor.Gray);
                    }
                    isConnected = true;
                }
                catch (Exception ex)
                {
                    LogToConsole(ex.Message, ConsoleColor.Yellow);
                }
            }
            else
            {
                isConnected = true;
            }

            if (isConnected)
            {
                // add data as a new row in DataTable
                m_perfDataBuffer.Rows.Add(DbUtility.ConvertToObjects(data, OperationContext.Current.SessionId));

                // save the whole buffer in database
                if (m_perfDataBuffer.Rows.Count >= SessionDataBufferMaxLength)
                {
                    DbUtility.BulkDatabaseSaveInTransaction(m_connection, m_perfDataBuffer);
                    m_perfDataBuffer.Rows.Clear();

                    LogToConsole("Bulk save transaction is finished", ConsoleColor.Gray);
                }
            }
        }

        public void FlushAndCloseSession()
        {
            if (m_perfDataBuffer != null && m_perfDataBuffer.Rows.Count > 0)
            {
                DbUtility.BulkDatabaseSaveInTransaction(m_connection, m_perfDataBuffer);
                m_perfDataBuffer.Rows.Clear();

                LogToConsole("Flush and close session", ConsoleColor.Gray);
            }
        }
    }
}
